﻿using System;
using System.Linq;
using System.Windows.Forms;
using DesignerHelper.EventHandlers;
using DesignerHelper.Main;
using SpreadsheetGear;
using SpreadsheetGear.Windows.Forms;
using WorkbookDesigner.Addons.WorkbookExplorer.Model;
using WorkbookDesigner.Main;

namespace WorkbookDesigner.Addons.WorkbookExplorer
{
    public partial class WbExplorer : Form
    {
        #region 窗口唯一

        private static WbExplorer _wbExplorer;

        /// <summary>
        ///
        /// </summary>
        /// <param name="owner">程序主窗体实例</param>
        /// <param name="withPage">选择打开窗口时默认显示的页面</param>
        public static void GetInstance(IMainWindow mw, StartWith withPage = StartWith.NamesInBook)
        {
            if (_wbExplorer == null)
            {
                _wbExplorer = new WbExplorer(mw, withPage)
                {
                    FileOperator = mw.FileOperator,
                };
                _wbExplorer.Show(mw.GetForm());
            }
            else
            {
                _wbExplorer.Activate();
                _wbExplorer.StartWithPage(withPage);
            }
        }

        #endregion 窗口唯一

        private WbExplorer()
        {
            InitializeComponent();
        }

        private WbExplorer(IMainWindow mw, StartWith with) : this()
        {
            Mw = mw;
            TriggerInit();
            StartWithPage(with);
        }


        private event BookSetEventHandler BookSetIsModified;

        public enum StartWith
        {
            /// <summary>
            /// 显示当前工作簿中定义的名称
            /// </summary>
            NamesInBook,

            /// <summary>
            /// 显示当前工作表中定义的名称
            /// </summary>
            NamesInSheet,

            /// <summary>
            /// 工作簿选项设置页
            /// </summary>
            WorkbookOptions,

            /// <summary>
            /// 工作表选项设置页
            /// </summary>
            WorkSheetOptions,

            /// <summary>
            /// 工作表分级显示选项设置页
            /// </summary>
            Outline,

            /// <summary>
            /// 工作表页面设置页
            /// </summary>
            PageSetup
        }

        private IWorkbooks Workbooks => BookSet.Workbooks;

        private WorkbookView ActiveView { get; set; }

        private IWorkbookSet BookSet => Mw.FileOperator.MainBookSet;

        private TreeNode BookSetNode { get; set; }

        private TreeNode LastSelectedNode { get; set; }


        private IMainWindow Mw { get; }
        private IFileOperator FileOperator { get; set; }

        private TreeNode SelectedNode
        {
            get { return treeViewBase.SelectedNode; }
            set
            {
                treeViewBase.SelectedNode = value;
                FormatNodeFont();
            }
        }

        private UcFactory Usc { get; set; }

        private void OnBookSetIsModified(BookSetEventArgs e)
        {
            BookSetIsModified?.Invoke(this, e);
        }

        private void AddToControlPanel(Control uc)
        {
            panelControls.Controls.Add(uc);
        }


        private void ClearControlPanel()
        {
            panelControls.Controls.Clear();
        }

        private void BeginInit()
        {
            treeViewBase.Enabled = true;
            //panel1展开
            splitContainer1.Panel1Collapsed = false;
            splitContainer1.SplitterDistance = 170;
            DrawTreeView();
        }

        private void DrawTreeView()
        {
            BookSet.DoWork(InitTreeNodes);
        }

        private void HookEvents()
        {
            Mw.FileOperator.BookSetModified += RefreshTreeView;
            BookSetIsModified += RefreshTreeView;
        }

        private void InitTreeNodes()
        {
            treeViewBase.Nodes.Clear();
            BookSetNode = new TreeNode("所有工作簿")
            {
                Name = "BookSetNode",
                Tag = BookSet,
            };
            TreeNode[] allBookNode = TreeNodeBusiness.GetWorkbookNodes(Workbooks);
            BookSetNode.Nodes.AddRange(allBookNode);
            treeViewBase.Nodes.Add(BookSetNode);
            BookSetNode.Expand();
        }

        private bool RefreshSuccessed()
        {
            RefreshWbv();
            return ActiveView != null;
        }

        private void RefreshTreeView(object sender, BookSetEventArgs e)
        {
            DrawTreeView();
            if (e.ActiveWorkbookInternal == null)
            {
                Init4TreeNodeLv0();
                return;
            }
            if (e.ActiveWorksheetInternal == null) //ps 需要修改 事件本身需要重写
                Init4SpeNodeLv1(Mw.ActiveBookForm.ActiveBook);
            else
                Init4SpeNodeLv2(Mw.ActiveBookForm.ActiveWorkSheet);
        }

        private void RefreshWbv()
        {
            ActiveView = Mw.ActiveView;
        }

        private void StartWithPage(StartWith sw)
        {
            if (!RefreshSuccessed())
                return;
            switch (sw)
            {
                case StartWith.NamesInBook:
                case StartWith.WorkbookOptions:
                    StartWithWorkbookPage(sw);
                    break;
                case StartWith.NamesInSheet:
                case StartWith.Outline:
                case StartWith.PageSetup:
                case StartWith.WorkSheetOptions:
                    StartWithWorksheetPage(sw);
                    break;
            }
        }

        private void StartWithWorkbookPage(StartWith page)
        {
            BookSet.DoWork(() => { Init4SpeNodeLv1(ActiveView.ActiveWorkbook, page); });
        }

        private void StartWithWorksheetPage(StartWith page)
        {
            BookSet.DoWork(() => { Init4SpeNodeLv2(ActiveView.ActiveWorksheet, page); });
        }

        #region MenuItem菜单事件

        private void toolStripMenuItemClose_Click(object sender, EventArgs e)
        {
            BookSet.DoWork(() =>
            {
                IWorkbook workbook = GetWorkBook(SelectedNode);
                if (workbook != null)
                    FileOperator.Close(workbook);
            });
        }

        private void toolStripMenuItemCopyWorksheet_Click(object sender, EventArgs e)
        {
            IWorksheet worksheet = GetWorkSheet(SelectedNode);
            if (worksheet == null) return;
            BookSet.DoWork(() =>
            {
                IWorksheet sheet = worksheet.CopyAfter(worksheet) as IWorksheet;
                if (sheet != null)
                    OnBookSetIsModified(new BookSetEventArgs(sheet, BookSetEventArgs.Type.Add));
            });
        }

        private void toolStripMenuItemDeleteWorksheet_Click(object sender, EventArgs e)
        {
            IWorksheet worksheet = GetWorkSheet(SelectedNode);
            if (worksheet == null) return;

            IWorkbook book = worksheet.Workbook;
            BookSet.DoWork(() => worksheet.Delete());
            OnBookSetIsModified(new BookSetEventArgs(book, BookSetEventArgs.Type.Remove));
        }

        private void toolStripMenuItemInsertWorksheet_Click(object sender, EventArgs e)
        {
            IWorksheet worksheet = GetWorkSheet(SelectedNode);
            if (worksheet == null) return;
            BookSet.DoWork(() =>
            {
                IWorksheets sheets = worksheet.Workbook.Worksheets;
                IWorksheet newSheet = sheets.AddBefore(worksheet);
                OnBookSetIsModified(new BookSetEventArgs(newSheet, BookSetEventArgs.Type.Add));
            });
        }

        private void toolStripMenuItemNewWorkbook_Click(object sender, EventArgs e)
        {
            BookSet.DoWork(() =>
            {
                IWorkbook workbook = BookSet.Workbooks.Add();
                FileOperator.OpenFile(workbook);
            });
        }

        private void toolStripMenuItemNewWorksheet_Click(object sender, EventArgs e)
        {
            IWorkbook workbook = GetWorkBook(SelectedNode);
            if (workbook == null) return;
            BookSet.DoWork(() =>
            {
                OnBookSetIsModified(new BookSetEventArgs(workbook.Worksheets.Add(), BookSetEventArgs.Type.Add));
            });
        }

        private void toolStripMenuItemOpenWorkbook_Click(object sender, EventArgs e)
        {
            FileOperator.OpenFiles();
        }

        private void toolStripMenuItemRenameWorksheet_Click(object sender, EventArgs e)
        {
            IWorksheet worksheet = GetWorkSheet(SelectedNode);
            if (worksheet == null) return;
            treeViewBase.LabelEdit = true;
            SelectedNode.BeginEdit();
        }

        private void toolStripMenuItemSave_Click(object sender, EventArgs e)
        {
            IWorkbook workbook = GetWorkBook(SelectedNode);
            if (workbook == null) return;
            BookSet.DoWork(() =>
            {
                IBookForm bf = Mw.FileOperator.AllFormsList.FirstOrDefault(x => x.ActiveBook == workbook);
                if (bf == null)
                    return;
                bf.SaveFile();
            });
        }

        private void toolStripMenuItemSaveAs_Click(object sender, EventArgs e)
        {
            BookSet.DoWork(() =>
            {
                IWorkbook workbook = GetWorkBook(SelectedNode);
                if (workbook == null) return;
                IBookForm bf = Mw.FileOperator.AllFormsList.FirstOrDefault(x => x.ActiveBook == workbook);
                if (bf == null)
                    return;
                bf.FileSaveAs();
            });
        }

        #endregion

        private void treeViewBase_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            IWorksheet worksheet = GetWorkSheet(SelectedNode);
            if (worksheet == null) return;
            if (string.IsNullOrEmpty(e.Label))
            {
                if (e.Label == "")
                    DesignerHelper.Help.MesBox.ErrorMessage("输入名称不能为空!");
                e.CancelEdit = true;
                treeViewBase.LabelEdit = false;
                return;
            }
            BookSet.DoWork(() => { worksheet.Name = e.Label; });
            treeViewBase.LabelEdit = false;
        }

        private void treeViewBase_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            TriggerInit4TreeNode(e.Node);
        }

        private void TriggerInit()
        {
            ActiveView = Mw.ActiveView;
            Usc = new UcFactory(Mw.FileOperator.AllFormsList);
            BeginInit();
            HookEvents();
        }

        private void UnhookEvents()
        {
            Mw.FileOperator.BookSetModified -= RefreshTreeView;
            BookSetIsModified -= RefreshTreeView;
        }

        private void WorkbookExplorer_FormClosed(object sender, FormClosedEventArgs e)
        {
            ClearControlPanel();
            UnhookEvents();
            _wbExplorer = null;
        }

        #region Init And Draw TreeView

        private void Init4SpeNodeLv1(IWorkbook workbook, StartWith ps = StartWith.NamesInBook)
        {
            TreeNode node = GetTreeNode(workbook);
            treeViewBase.CollapseAll();
            node.EnsureVisible();
            node.Expand();
            SelectedNode = node;
            LastSelectedNode = SelectedNode;
            int index = 0;
            switch (ps)
            {
                case StartWith.NamesInBook:
                    break;
                case StartWith.WorkbookOptions:
                    index = 1;
                    break;
                default:
                    index = 0;
                    break;
            }
            Init4TreeNodeLv1(workbook, index);
        }

        private void Init4SpeNodeLv2(IWorksheet worksheet, StartWith ps = StartWith.NamesInSheet)
        {
            TreeNode node = GetTreeNode(worksheet);
            treeViewBase.CollapseAll();
            node.Parent.Expand();
            node.EnsureVisible();
            SelectedNode = node;
            LastSelectedNode = SelectedNode;

            int index = 0;
            switch (ps)
            {
                case StartWith.NamesInSheet:
                    break;
                case StartWith.WorkSheetOptions:
                    index = 1;
                    break;
                case StartWith.Outline:
                    index = 2;
                    break;
                case StartWith.PageSetup:
                    index = 3;
                    break;
                default:
                    index = 0;
                    break;
            }
            Init4TreeNodeLv2(worksheet, index);
        }

        private void Init4TreeNodeLv0()
        {
            TreeNode node = treeViewBase.Nodes[0];
            SelectedNode = node;
            ClearControlPanel();
            Usc.BookSetOptions.TriggerInit(BookSet);
            AddToControlPanel(Usc.BookSetOptions);
        }

        private void Init4TreeNodeLv1(IWorkbook workbook, int index = 0)
        {
            ClearControlPanel();
            //todo 更新方法
            BaseTab tab = Usc.GetBaseTab(workbook);
            tab.SetChildTabControlIndex(index);
            AddToControlPanel(tab);
        }

        private void Init4TreeNodeLv2(IWorksheet worksheet, int index = 0)
        {
            ClearControlPanel();
            BaseTab tab = Usc.GetBaseTab(worksheet);
            tab.SetChildTabControlIndex(index);
            AddToControlPanel(tab);
        }

        private void FormatNodeFont()
        {
            if (LastSelectedNode != null)
                LastSelectedNode.NodeFont = TreeNodeBusiness.RegularFont;
            if (SelectedNode != null)
                SelectedNode.NodeFont = TreeNodeBusiness.BoldFont;
        }

        private void TriggerInit4TreeNode(TreeNode node)
        {
            ClearControlPanel();
            node.EnsureVisible();
            SelectedNode = node;
            switch (node.Level)
            {
                case 2:
                    {
                        treeViewBase.ContextMenuStrip = contextMenuStripNodeWorksheet;
                        IWorksheet sheet = GetWorkSheet(node);
                        if (sheet != null)
                            Init4TreeNodeLv2(sheet);
                    }
                    break;

                case 1:
                    {
                        treeViewBase.ContextMenuStrip = contextMenuStripNodeWorkbook;
                        IWorkbook book = GetWorkBook(node);
                        if (book != null)
                            Init4TreeNodeLv1(book);
                    }
                    break;

                case 0:
                    {
                        treeViewBase.ContextMenuStrip = contextMenuStripBase;
                        Init4TreeNodeLv0();
                    }
                    break;
            }
            LastSelectedNode = node;

            Refresh();
        }

        #endregion Init And Draw TreeView

        #region Node、Book、sheet相互查找/增删

        private IWorkbook GetWorkBook(TreeNode selectedNode)
        {
            var bookModel = selectedNode as BookModel;
            return bookModel?.Workbook;
        }

        private TreeNode GetTreeNode(IWorkbook workbook)
        {
            return BookSetNode.Nodes.OfType<BookModel>().FirstOrDefault(x => x.Workbook == workbook);
        }

        private TreeNode GetTreeNode(IWorksheet worksheet)
        {
            TreeNode booknode = GetTreeNode(worksheet.Workbook);
            // ReSharper disable once PossibleUnintendedReferenceComparison
            var results =
                booknode.Nodes.OfType<SheetModel>().Where(x => x.Worksheet == worksheet);
            // ReSharper disable once PossibleUnintendedReferenceComparison
            TreeNode sheet = results.FirstOrDefault(x => x.Worksheet == worksheet && x.Level == 2);
            return sheet;
        }

        private IWorksheet GetWorkSheet(TreeNode selectedNode)
        {
            var sheet = selectedNode as SheetModel;
            return sheet?.Worksheet;
        }

        #endregion Node、Book、sheet相互查找/增删
    }
}